home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / C / Code Resources / Jims CDEFs 1.50 / CDEF Source / source / cdefDtc.c < prev    next >
Encoding:
Text File  |  1995-11-08  |  39.4 KB  |  1,352 lines  |  [TEXT/KAHL]

  1. //----------------------- © 1992-1995 by James G. Stout ----------------------------
  2. // File        : cdefDtc.c
  3. // Date        : 20 June 1992
  4. // Author    : Jim Stout
  5. //            :
  6. // Purpose    : a "Date Time Control" CDEF that allows adjustment of date
  7. //            : and time as in the General Control Panel. Clicking on the
  8. //            : date or time will show a 'small arrow' type control for
  9. //            : date or time adjustment.
  10. //            :
  11. //            : see cdefDtc.h for more detail and variation codes
  12. //            :
  13. //            : If you find a use for this, I'd love to know about it.  Bug reports
  14. //            : are always interesting.
  15. //            :
  16. //            : Internet    : JimS@WRQ.COM(work hours, PST)
  17. //            : AppleLink   : WRQ            (daily)
  18. //            : CompuServe  : 73240,2052    (weekly or so)
  19. //            : AOL         : JasG        (weekly or so)
  20. //            : eWorld      : Jim Stout    (weekly or so)
  21. //----------------------------------------------------------------------------------
  22. //#define _DEBUGCDEF 1
  23.  
  24.  
  25. #include "fatCDEF.h"
  26.  
  27. #include <Controls.h>
  28. #include <GestaltEqu.h>
  29. #include <LowMem.h>
  30. #include <Memory.h>
  31. #include <Packages.h>
  32. #include <QDOffscreen.h>
  33. #include <ToolUtils.h>
  34. #include <Types.h>
  35.  
  36. #include "colorCDEF.h"
  37. #include "grayCDEF.h"
  38. #include "miscCDEF.h"
  39. #include "qdCDEF.h"
  40.  
  41. #include "cdefDtc.h"
  42.  
  43. #ifdef _DEBUGCDEF
  44. pascal long CDmain (short, ControlHandle, short, long);
  45.  
  46. pascal long CDmain (short varCode, ControlHandle theCtl, short message, long param)
  47. #else
  48.  
  49. //==================================================================================
  50. // CDEF entry point
  51. //==================================================================================
  52. pascal long main (short varCode, ControlHandle theCtl, short message, long param)
  53. #endif
  54. {
  55.     long        ret = 0L;
  56.     short        txF, txS, partCode,myVarCode=0;
  57.     GrafPtr        thisPort;
  58.     SignedByte    cState, dState;
  59.         
  60. #include "fatEntry.c"
  61.     
  62.     cState = HGetState((Handle)theCtl);
  63.     HLock((Handle)theCtl);
  64.     
  65. //----------------------------------------------------------------------------------
  66. // make sure we've got the correct font…
  67. //----------------------------------------------------------------------------------    
  68.  
  69.     if(!(varCode & useWindFont)) {                    // don't use the window font    
  70.         GetPort(&thisPort);
  71.         txF = thisPort->txFont;
  72.         txS = thisPort->txSize;
  73.         TextFont(LMGetSysFontFam());                // set system as current
  74.         TextSize(LMGetSysFontSize());
  75.     }
  76.  
  77. //----------------------------------------------------------------------------------
  78. // lock down the cdef data and get our 'custom' variation code
  79. //----------------------------------------------------------------------------------    
  80.  
  81.     if((**theCtl).contrlData) {
  82.         dState = HGetState((**theCtl).contrlData);
  83.         HLock((**theCtl).contrlData);
  84.         myVarCode = (**(dtcHandle)(**theCtl).contrlData).varCode;
  85.     }
  86.     
  87.     partCode = LoWord(param);
  88.     
  89. //----------------------------------------------------------------------------------
  90. // handle the standard control messages    
  91. //----------------------------------------------------------------------------------
  92.     
  93.     switch(message) {
  94.         case initCntl:
  95.             doInit(theCtl, varCode);
  96.             if((**theCtl).contrlData) {
  97.                 dState = HGetState((**theCtl).contrlData);
  98.                 HLock((**theCtl).contrlData);
  99.             }
  100.         break;
  101.         case dispCntl:
  102.             doDisp(theCtl);
  103.         break;
  104.         case testCntl:
  105.             ret = doTest (theCtl, myVarCode, param);
  106.         break;
  107.         case drawCntl:
  108.             if((**theCtl).contrlVis != 0 &&
  109.                 ((WindowPeek)(**theCtl).contrlOwner)->visible) {
  110.                 doDraw(theCtl, myVarCode, partCode);
  111.             }
  112.         break;
  113.         case calcCRgns:
  114.             RectRgn((RgnHandle)(param & 0x7fffffffL), &(**theCtl).contrlRect);
  115.         break;
  116.         case calcCntlRgn:
  117.         case calcThumbRgn:
  118.             RectRgn((RgnHandle)(param), &(**theCtl).contrlRect);
  119.         break;
  120.     }
  121.     
  122. //----------------------------------------------------------------------------------
  123. // restore window font & size info    
  124. //----------------------------------------------------------------------------------
  125.  
  126.     if(!(varCode & useWindFont)) {
  127.         TextFont(txF);
  128.         TextSize(txS);
  129.     }
  130.  
  131.     if((**theCtl).contrlData)
  132.         HSetState((**theCtl).contrlData, dState);
  133.     HSetState((Handle)theCtl, cState);
  134.     
  135. #include "fatExit.c"
  136.  
  137.     return (ret);
  138. }
  139.  
  140. //==================================================================================
  141. //    initialize our data
  142. //==================================================================================
  143.  
  144. static void doInit        (ControlHandle theCtl, short varCode)
  145. {
  146.     dtcHandle    hCDEF;
  147.     Intl0Hndl    hInt;
  148.     short        inx;
  149.  
  150.     hCDEF = (dtcHandle) NewHandle(sizeof(dtcData));
  151.     if(hCDEF) {
  152.         for(inx=0;inx<6;inx++)
  153.             (**hCDEF).poly[inx] = 0;
  154.         (**hCDEF).arrowHilite = 0;
  155.         (**hCDEF).varCode = varCode;                // save original varCode            
  156.         (**hCDEF).qdVers = getQDVers();                // QuickDraw version                
  157.         (**hCDEF).offPort = 0;                        // gets created in doDraw            
  158.         (**hCDEF).pDepth = 1;            
  159.         (**hCDEF).currSel = 0;
  160.         
  161.         hInt = (Intl0Hndl)IUGetIntl(0);
  162.         
  163.         (**hCDEF).dateSep = (**hInt).dateSep;
  164.         (**hCDEF).dateOrder = (**hInt).dateOrder;
  165.         (**hCDEF).timeSep = (**hInt).timeSep;
  166.         (**hCDEF).timeCycle = (**hInt).timeCycle;
  167.         
  168. //----------------------------------------------------------------------------------
  169. // contrlMax & controlMin are used as "extended" variation codes
  170. //----------------------------------------------------------------------------------
  171.  
  172.         if(!(**theCtl).contrlMax) {                    // use ControlPanel 12/24 setting
  173.             if((**hInt).timeCycle != 0)                // set for AM/PM
  174.                 (**hCDEF).varCode ^= showAMPM;        // so, set our varCode        
  175.         }
  176.         (**theCtl).contrlMax = 9;
  177.     
  178.         if((**theCtl).contrlMin) {                    // if non-zero, wants 3D arrows
  179.             (**hCDEF).varCode ^= ctl3D;                // so, set our varCode
  180.             (**theCtl).contrlMin = 0;
  181.         }
  182.         (**theCtl).contrlData = (Handle)hCDEF;
  183.     }
  184.     else
  185.         (**theCtl).contrlData = 0;
  186. }
  187.  
  188. //==================================================================================
  189. //    dispose of our data
  190. //==================================================================================
  191.  
  192. static void doDisp        (ControlHandle theCtl)
  193. {
  194.     dtcHandle    hCDEF;
  195.     short        inx;
  196.     BitMap        *theBits;
  197.     
  198.     hCDEF = (dtcHandle)(**theCtl).contrlData;
  199.     if(hCDEF) {
  200.         if((**hCDEF).offPort) {
  201.             if(((**hCDEF).offPort->portVersion & 0x8000) != 0) {    // offPort is GWorld
  202.                 DisposeGWorld((**hCDEF).offPort);                
  203.             }
  204.             else {                                                    // offport is bitmap
  205.                 theBits = &((GrafPtr)(**hCDEF).offPort)->portBits;
  206.                 DisposePtr((*theBits).baseAddr);
  207.                 ClosePort((GrafPtr)(**hCDEF).offPort);
  208.                 DisposePtr((Ptr)(**hCDEF).offPort);
  209.             }
  210.         }    
  211.                 
  212.         for(inx=0;inx<6;inx++) {
  213.             if((**hCDEF).poly[inx])
  214.                 KillPoly((**hCDEF).poly[inx]);
  215.         }
  216.         HUnlock((Handle)hCDEF);
  217.         DisposeHandle((Handle)hCDEF);
  218.         (**theCtl).contrlData = 0;
  219.     }
  220. }
  221.  
  222. //==================================================================================
  223. //    check for a mouseDown in our control    
  224. //==================================================================================
  225.  
  226. static long doTest (ControlHandle theCtl, short varCode, long param)
  227. {
  228.     Point        p;
  229.     short        inx,start, end;
  230.     long        ret=0L;
  231.     Rect        parts[NUMPARTS];
  232.     Boolean     hit;
  233.     dtcHandle    hCDEF;
  234.     
  235.     hCDEF = (dtcHandle)(**theCtl).contrlData;
  236.     if(!hCDEF)
  237.         return(ret);
  238.     
  239.     p.h = LoWord(param);                                    // get the mouse hit point        
  240.     p.v = HiWord(param);
  241.     
  242.     start = HOURS;                                            // set loop variables            
  243.     end = DOWNDATE;
  244.  
  245.     if(varCode & timeOnly)
  246.         end = DOWNTIME;
  247.     else
  248.     if(varCode & dateOnly)
  249.         start = DT1;
  250.  
  251.     if(PtInRect(p,&(**theCtl).contrlRect)) {                // click in control                
  252.         getRects(theCtl, varCode, parts);
  253.         (**hCDEF).arrowHilite = 0;                            // arrow not hilited
  254.         
  255. //----------------------------------------------------------------------------------
  256. // first, test for a simple click in one of the digit fields
  257. //----------------------------------------------------------------------------------
  258.  
  259.         for(inx = start;inx <= end;inx++) {                    // loop through all parts        
  260.             if(PtInRect(p,&parts[inx])) {                    // and check for a mouse down
  261.                 if(!arrowPart(inx))    {                        // click in a digit, not in
  262.                     while(StillDown()) {                    // an arrow.
  263.                     }
  264.                     GetMouse(&p);
  265.                     if(PtInRect(p,&parts[inx])) {
  266.                         (**theCtl).contrlValue = inx;
  267.                         return((long)inx);                    // all done
  268.                     }
  269.                     else
  270.                         return (0L);
  271.                 }
  272.             }
  273.         }
  274.  
  275. //----------------------------------------------------------------------------------
  276. // second, check for a click in an arrow
  277. //----------------------------------------------------------------------------------
  278.                     
  279.         if((**theCtl).contrlValue) {                        // an arrow is visible
  280.             if((**theCtl).contrlValue <= AMPM) {            // time arrow
  281.                 start = UPTIME;
  282.                 end = DOWNTIME;
  283.             }
  284.             else {                                            // date arrow
  285.                 start = UPDATE;
  286.                 end = DOWNDATE;
  287.             }
  288.             for (inx=start;inx<=end;inx++) {                // check for press in arrow
  289.                 if(PtInRect(p,&parts[inx])) {                
  290.                     while (StillDown()) {                    // and track it…        
  291.                         if(PtInRect(p,&parts[inx]))    {        // mouse hasn't moved… so    
  292.                             (**hCDEF).arrowHilite = inx;        // hilite & update value…
  293.                             updateValue (theCtl, varCode, inx);
  294.                             hit = true;
  295.                             ret = (long)inx;
  296.                         }
  297.                         else                                                
  298.                         if(hit) {                            // mouse moved outside arrow    
  299.                             (**hCDEF).arrowHilite = 0;        // so un-hilite arrow…
  300.                             doDraw(theCtl, varCode, ALL);
  301.                             hit = false;
  302.                             ret = 0L;
  303.                         }
  304.                         GetMouse(&p);                        // get new mouse location    
  305.                     }
  306.                 }
  307.             }
  308.             if(hit) {                                        // un-hilite arrow, mouse
  309.                 (**hCDEF).arrowHilite = 0;                    // came up...
  310.                 doDraw(theCtl, varCode, ALL);
  311.                 ret = 0;
  312.             }
  313.         }
  314.     }
  315.     return(ret);
  316. }
  317.  
  318. //==================================================================================
  319. //    update the control value    
  320. //==================================================================================
  321.  
  322. static void updateValue    (ControlHandle theCtl, short varCode, short partCode)
  323. {
  324.     short            selected,m,d,y,dateTbl[3];
  325.     unsigned long    secs;
  326.     DateTimeRec        dtr;
  327.     dtcHandle    hCDEF;
  328.     
  329.     hCDEF = (dtcHandle)(**theCtl).contrlData;
  330.     if(!hCDEF)
  331.         return;
  332.     
  333.     if(!arrowPart(partCode))                // only track the up/down arrows            
  334.         return;
  335.     
  336.     selected = (**theCtl).contrlValue;        // the item to adjust                        
  337.     secs = GetCRefCon(theCtl);                // get current date/time setting            
  338.     Secs2Date(secs,&dtr);                    // convert to a DateTimeRecord                
  339.     
  340.     getDateFmt(theCtl, &m, &d, &y);
  341.     dateTbl[d] = dtr.day;
  342.     dateTbl[m] = dtr.month;
  343.     dateTbl[y] = dtr.year;
  344.     
  345.     switch(selected) {                        // now, bump the selected item up or down    
  346.         case MINUTES:
  347.             if(partCode == UPTIME)
  348.                 secs += 60;
  349.             else
  350.                 secs -= 60;
  351.         break;
  352.         case HOURS:
  353.             if(partCode == UPTIME)
  354.                 secs += 3600;
  355.             else
  356.                 secs -= 3600;
  357.         break;
  358.         case AMPM:
  359.             if(dtr.hour < 12)
  360.                 dtr.hour+=12;
  361.             else
  362.                 dtr.hour-=12;
  363.         break;
  364.         case DT1:
  365.             if(partCode == UPDATE)
  366.                 dateTbl[m]++;
  367.             else
  368.                 dateTbl[m]--;
  369.             if(dateTbl[m] > 12) {
  370.                 dateTbl[y]++;
  371.                 dateTbl[m] = 1;
  372.             }
  373.             else
  374.             if(dateTbl[m] < 1) {
  375.                 dateTbl[y]--;
  376.                 dateTbl[m] = 12;
  377.             }
  378.         break;
  379.         case DT2:
  380.             if(partCode == UPDATE)
  381.                 dateTbl[d]++;
  382.             else
  383.                 dateTbl[d]--;
  384.         break;
  385.         case DT3:
  386.             if(partCode == UPDATE)
  387.                 dateTbl[y]++;
  388.             else
  389.             if(dateTbl[y] > 1904)                // ROM routine only good since 1904,    
  390.                 dateTbl[y]--;                    // the year the Mac was invented !        
  391.         break;
  392.     }
  393.     dtr.day = dateTbl[d];
  394.     dtr.month = dateTbl[m];
  395.     dtr.year = dateTbl[y];
  396.     
  397.     if(selected != HOURS && selected != MINUTES)
  398.         Date2Secs(&dtr, &secs);                    // convert date rec back to seconds        
  399.         
  400.     SetCRefCon(theCtl,secs);                    // save the new date & time    
  401.     doDraw(theCtl, varCode, ALL);                // draw the new date & time    
  402.     Delay(10L, (long *)&secs);                    // pause a bit                     
  403. }
  404.  
  405. //==================================================================================
  406. //    process the drawCntl message    
  407. //==================================================================================
  408.  
  409. void doDraw(ControlHandle theCtl, short varCode, short partCode)
  410. {
  411.     WindowPeek            w;
  412.     RgnHandle             saveClip, newClip;
  413.     Boolean                inactive=false,inColor=false,bgInColor=false;
  414.     Boolean                haveGW=false,haveGray=false, backPat=false;
  415.     PenState            penSt;
  416.     unsigned long        secs;
  417.     short                h,v,oldVal,toDraw;
  418.     Str31                s1;
  419.     Rect                r;
  420.     BitMap                *offBits;
  421.     Rect                parts[NUMPARTS];
  422.     CGrafPtr            savePort;
  423.     GDHandle            saveGDev;
  424.     PixMapHandle        pmHdl;
  425.     RGBColor            saveFore,saveBack;
  426.     RGBColor            rgbBlack = {0,0,0};
  427.     RGBColor            rgbWhite = {-1,-1,-1};
  428.     dtcHandle            hCDEF;
  429.     
  430.     hCDEF = (dtcHandle)(**theCtl).contrlData;
  431.     if(!hCDEF)
  432.         return;
  433.         
  434.     w = (WindowPeek)(**theCtl).contrlOwner;                    // don't draw if window is    
  435.     if(!w->visible || arrowPart(partCode))    {                // invisible or if partCode    
  436.         return;                                                // is an up/down arrow        
  437.     }            
  438.     if((**theCtl).contrlHilite == 0xFF) {
  439.         inactive = true;
  440.     }
  441.     else                            
  442.     if((**theCtl).contrlHilite > 0 &&                        // we hilite differently     
  443.         !arrowPart((short)(**theCtl).contrlHilite)) {        // from normal controls        
  444.         return;                                            
  445.     }
  446.     
  447.     if(partCode == 129)
  448.         partCode = (**theCtl).contrlValue;
  449.         
  450.     getRects(theCtl, varCode, parts);                        // rects for control parts    
  451.     
  452. //----------------------------------------------------------------------------------
  453. // now, update our GWorld if required, and set it as our drawing port    
  454. //----------------------------------------------------------------------------------
  455.  
  456.     (**hCDEF).pDepth = getOff(&(**hCDEF).offPort, &parts[ALL]);
  457.     
  458.     if((**hCDEF).pDepth == 0) {                                // oh… oh…                
  459.         return;                
  460.     }
  461.     
  462.     if(((**hCDEF).offPort->portVersion & 0x8000) != 0) {    // have a GWorld
  463.         haveGW = true;
  464.         pmHdl = getLockedPixels(&(**hCDEF).offPort, (**hCDEF).qdVers);
  465.         if(!pmHdl)
  466.             return;                                            // nuts…
  467.     }
  468.  
  469. //----------------------------------------------------------------------------------
  470. //    Do the clip region properly.  Thanks Ari!
  471. //----------------------------------------------------------------------------------
  472.  
  473.     r = (**theCtl).contrlRect;                                // the rect we draw in    
  474.     saveClip = NewRgn();
  475.     GetClip(saveClip);
  476.     
  477.     newClip = NewRgn();
  478.     RectRgn(newClip, &r);
  479.     SectRgn(saveClip, newClip, newClip);
  480.     
  481.     if(EmptyRgn(newClip)) {                                    // if empty, don't waste
  482.         DisposeRgn(saveClip);                                // time drawing...
  483.         DisposeRgn(newClip);
  484.         return;
  485.     }
  486.  
  487.     SetClip(newClip);
  488.     
  489. //----------------------------------------------------------------------------------
  490. // initialize our drawing stuff    
  491. //----------------------------------------------------------------------------------
  492.  
  493.     if((**hCDEF).pDepth > 2) {                                // save current port
  494.         inColor = true;                                        // colors
  495.         saveColors(&saveFore, &saveBack);
  496.         bgInColor = true;
  497.         if(saveBack.red == 65535 &&                            // is bg white?
  498.             saveBack.green == 65535 &&
  499.             saveBack.blue == 65535)
  500.             bgInColor = false;
  501.     }    
  502. #ifdef NOEMBOSS
  503.     bgInColor = false;
  504. #endif
  505.  
  506. //----------------------------------------------------------------------------------
  507. // Set for drawing in offscreen port
  508. //----------------------------------------------------------------------------------
  509.     if(haveGW) {                                            // set offscreen for drawing
  510.         GetGWorld(&savePort, &saveGDev);    
  511.         SetGWorld((**hCDEF).offPort, nil);
  512.     } else {
  513.         GetPort((GrafPtr*)&savePort);
  514.         SetPort((GrafPtr)(**hCDEF).offPort);
  515.     }
  516.     if(inColor) {                                            // set colors in offPort    
  517.         RGBForeColor(&saveFore);
  518.         RGBBackColor(&saveBack);
  519.         setPartColor(theCtl, cTextColor, true);
  520.     }
  521.     else {
  522.         ForeColor(blackColor);
  523.         BackColor(whiteColor);
  524.     }
  525.     if(varCode & useWindFont) {                                // set font in offPort        
  526.         (**hCDEF).offPort->txFont = savePort->txFont;
  527.         (**hCDEF).offPort->txSize = savePort->txSize;
  528.     }
  529.     
  530.     if(haveGW) {                                            // we have a pixMap    
  531.         offBits = (BitMap *)*pmHdl;
  532.         if((**(*savePort).bkPixPat).patType != 0 &&
  533.             (savePort->portVersion & 0x8000) != 0) {
  534.             backPat = true;
  535.             BackPixPat((*savePort).bkPixPat);        
  536.         }    
  537.     }
  538.     else {                                                    // we have a bitMap            
  539.         offBits = (BitMap *)&((GrafPtr)(**hCDEF).offPort)->portBits;
  540.     }
  541.  
  542. //----------------------------------------------------------------------------------
  543. //    Erase background of offscreen port - pay attention to origin so patterned
  544. //    backgrounds are aligned
  545. //----------------------------------------------------------------------------------
  546.  
  547.         SetOrigin((**theCtl).contrlRect.left, (**theCtl).contrlRect.top);
  548.         EraseRect(&(**theCtl).contrlRect);
  549.         SetOrigin(0,0);
  550.             
  551. //----------------------------------------------------------------------------------
  552. // Draw the control title
  553. //----------------------------------------------------------------------------------
  554.  
  555.     OffsetRect(&parts[TITLE], -parts[ALL].left, -parts[ALL].top);
  556.     h = parts[TITLE].left + 1;
  557.     v = parts[TITLE].bottom-parts[FONTINFO].bottom;
  558.     if(bgInColor && varCode & ctl3D) {
  559.         RGBForeColor(&rgbWhite);
  560.         MoveTo(h+1,v+1);
  561.         DrawString((**theCtl).contrlTitle);
  562.         setPartColor(theCtl, cTextColor, true);
  563.     }
  564.     if(inactive && inColor) {                                // control is inactive        
  565.         if(haveGrayText()) {                                // draw in gray
  566.             TextMode(grayishTextOr);
  567.             haveGray = true;
  568.         }
  569.     }
  570.     MoveTo(h,v);
  571.     DrawString((**theCtl).contrlTitle);                        // draw the title
  572.     TextMode(srcOr);
  573.     
  574. //----------------------------------------------------------------------------------
  575. // Get the refCon - our control 'value' or initialize if needed
  576. //----------------------------------------------------------------------------------
  577.  
  578.     secs = GetCRefCon(theCtl);                                // control 'value' in refCon    
  579.     if(secs == 0) {                                            // nothing there
  580.         GetDateTime(&secs);                        
  581.         SetCRefCon(theCtl, secs);                            // plug in current time
  582.     }
  583.  
  584. //----------------------------------------------------------------------------------
  585. // Convert to a date string and draw date
  586. //----------------------------------------------------------------------------------
  587.     
  588.     if(!(varCode & timeOnly)) {
  589.         getDateStr(theCtl, secs, s1);
  590.         OffsetRect(&parts[DATE], -parts[ALL].left, -parts[ALL].top);
  591.         h = parts[DATE].left + 1;
  592.         v = parts[DATE].bottom-parts[FONTINFO].bottom;
  593.         if(bgInColor && varCode & ctl3D) {                    // embossed 3D effect
  594.             RGBForeColor(&rgbWhite);
  595.             MoveTo(h+1,v+1);
  596.             DrawString(s1);
  597.             setPartColor(theCtl, cTextColor, true);
  598.         }
  599.         if(haveGray)                                        // means inactive
  600.             TextMode(grayishTextOr);
  601.         MoveTo(h,v);
  602.         DrawString(s1);
  603.         TextMode(srcOr);
  604.     }
  605.     
  606. //----------------------------------------------------------------------------------
  607. // Convert to a time string and draw time
  608. //----------------------------------------------------------------------------------
  609.  
  610.     if(!(varCode & dateOnly)) {
  611.         getTimeStr(theCtl, varCode, secs, s1);
  612.         OffsetRect(&parts[HOURS], -parts[ALL].left, -parts[ALL].top);
  613.         h = parts[HOURS].left + 1;
  614.         v = parts[HOURS].bottom-parts[FONTINFO].bottom;
  615.         if(bgInColor && varCode & ctl3D) {                    // embossed 3D effect
  616.             RGBForeColor(&rgbWhite);
  617.             MoveTo(h+1,v+1);
  618.             DrawString(s1);
  619.             setPartColor(theCtl, cTextColor, true);
  620.         }
  621.         if(haveGray)                                        // means inactive
  622.             TextMode(grayishTextOr);
  623.         MoveTo(h,v);
  624.         DrawString(s1);
  625.         TextMode(srcOr);
  626.     }
  627.     TextMode(srcOr);
  628.  
  629.     if(partCode == ALL)
  630.         oldVal = (**theCtl).contrlValue;
  631.     else
  632.     
  633. //----------------------------------------------------------------------------------
  634. // set new value for control - actually, this indicates the hilited digits, 
  635. // the actual dateTime value is stored in the control refcon!
  636. //----------------------------------------------------------------------------------    
  637.  
  638.     if(!arrowPart(partCode)) {
  639.  
  640. //----------------------------------------------------------------------------------
  641. // if inactive control, reset control value to deselect digits
  642. //----------------------------------------------------------------------------------
  643.  
  644.         if((**theCtl).contrlHilite == 0xFF) {    
  645.             (**hCDEF).currSel = (**theCtl).contrlValue = 0;    
  646.         }
  647.         else {
  648.         
  649. //----------------------------------------------------------------------------------
  650. // if click on currently selected digits, deselect & remove hiliting
  651. // by setting value to 0
  652. //----------------------------------------------------------------------------------
  653.  
  654.             if((**theCtl).contrlValue == partCode) {
  655.                 if((**hCDEF).currSel == (**theCtl).contrlValue) {        
  656.                     (**hCDEF).currSel = (**theCtl).contrlValue = 0;
  657.                 }
  658.                 else
  659.                     (**hCDEF).currSel = (**theCtl).contrlValue;
  660.             }
  661.  
  662. //----------------------------------------------------------------------------------
  663. // click on new digits, select by setting value to hilite
  664. //----------------------------------------------------------------------------------
  665.  
  666.             else {
  667.                 if(partCode < 0xFF) {
  668.                     if(partCode < 10)
  669.                         (**theCtl).contrlValue = partCode;
  670.                     (**hCDEF).currSel = 0;    
  671.                 }
  672.             }
  673.         }
  674.     }
  675.  
  676. //----------------------------------------------------------------------------------
  677. //     Draw the arrows into the offscreen port if needed
  678. //----------------------------------------------------------------------------------
  679.     if((**theCtl).contrlValue && !inactive) {                // only if selected    & active
  680.         
  681.         if(!(**hCDEF).poly[0])                                // create polygons for
  682.             makePolys(theCtl, varCode);                        // arrows
  683.             
  684.         if((**hCDEF).arrowHilite)                            // arrow to draw hilited
  685.             toDraw = (**hCDEF).arrowHilite;
  686.         else
  687.         if(partCode > 0 && partCode < 10)                                        
  688.             toDraw = partCode;                                // arrow not hilited
  689.         else
  690.             toDraw = (**theCtl).contrlValue;                // arrow not hilited
  691.     
  692.         drawArrows(theCtl, varCode, toDraw, inColor);
  693.     }
  694.  
  695. //----------------------------------------------------------------------------------
  696. // use CopyBits to draw the control onscreen
  697. //----------------------------------------------------------------------------------
  698.  
  699.     if(haveGW) {                                            // back to onscreen port    
  700.         SetGWorld(savePort, saveGDev);
  701.     } else {
  702.         SetPort((GrafPtr)savePort);
  703.     }
  704.     if(inColor) {
  705.         RGBForeColor(&rgbBlack);
  706.         RGBBackColor(&rgbWhite);
  707.     }
  708.     CopyBits(offBits,                                        // from bitmap                
  709.             &((GrafPtr)savePort)->portBits,                 // to onscreen port            
  710.             &(**hCDEF).offPort->portRect,                    // from rect                
  711.             &parts[ALL],                                     // to rect                    
  712.             srcCopy, nil);
  713.     
  714.     if(haveGW) {
  715.         unlockPixels(pmHdl, (**hCDEF).qdVers);
  716.         DisposeGWorld((**hCDEF).offPort);
  717.         (**hCDEF).offPort = 0;
  718.     }
  719.     if(inColor) {
  720.         restoreColors(&saveFore, &saveBack);
  721.     }
  722.  
  723. //----------------------------------------------------------------------------------
  724. // hilite the selected digits - contrlValue is currently selected field 
  725. //----------------------------------------------------------------------------------
  726.  
  727.     if(partCode == ALL)    {                                    // entire control redrawn    
  728.         if(oldVal)
  729.             doHilite(theCtl, varCode, oldVal, backPat);
  730.     }
  731.     else {
  732.         doHilite(theCtl, varCode,                             // hilite part clicked on
  733.             (**theCtl).contrlValue, backPat);        
  734.     }
  735.  
  736. //----------------------------------------------------------------------------------
  737. // if inactive & no GrayishTextOr, gray out the control the old way    
  738. //----------------------------------------------------------------------------------
  739.  
  740.     if(inactive && !haveGray) {
  741.         GetPenState(&penSt);    
  742.         PenPat( (ConstPatternParam) "\xAA\x55\xAA\x55\xAA\x55\xAA\x55");
  743.         PenMode(patBic);
  744.         PaintRect(&r);
  745.         SetPenState(&penSt);
  746.     }
  747.     
  748.     SetClip(saveClip);
  749.     DisposeRgn(saveClip);
  750.     DisposeRgn(newClip);
  751. }
  752.  
  753. //----------------------------------------------------------------------------------
  754. //    Hilite the digit parts of the control
  755. //----------------------------------------------------------------------------------
  756.  
  757. static void doHilite(ControlHandle theCtl, short varCode, short partCode,
  758.                         Boolean backPat)
  759. {    
  760.     Rect            parts[NUMPARTS];
  761.     dtcHandle        hCDEF;
  762.     unsigned char    hiliteMode;
  763.     
  764.     hCDEF = (dtcHandle)(**theCtl).contrlData;
  765.     if(!hCDEF)
  766.         return;
  767.     
  768.     if ((partCode >= HOURS && partCode <= AMPM) ||
  769.         (partCode >= DT1 && partCode <= DT3)) {
  770.         
  771.         getRects(theCtl, varCode, parts);
  772.         
  773.         if(backPat)
  774.             FrameRect(&parts[partCode]);
  775.         else {
  776.             hiliteMode = LMGetHiliteMode();
  777.             LMSetHiliteMode(pHiliteBit);
  778.             InvertRect(&parts[partCode]);
  779.             LMSetHiliteMode(hiliteMode);
  780.             ValidRect(&parts[partCode]);
  781.         }
  782.     }
  783. }
  784. //==================================================================================
  785. //    Draw the actual arrow control image.
  786. //    
  787. //==================================================================================
  788.  
  789. static void drawArrows(ControlHandle theCtl, short varCode, short toDraw, 
  790.                         Boolean inColor)
  791. {
  792.     short        inx,base;
  793.     Rect        arrowRect,parts[NUMPARTS];
  794.     RGBColor    rgbBlack = {0,0,0};
  795.     RGBColor    rgbWhite = {-1,-1,-1};
  796.     RGBColor    rgbA = {0xAAAA, 0xAAAA, 0xAAAA};
  797.     RGBColor    grayColor;
  798.     dtcHandle    hCDEF;
  799.     
  800.     hCDEF = (dtcHandle)(**theCtl).contrlData;
  801.     
  802.     getRects(theCtl, varCode, parts);                // rects for control parts
  803.     
  804.     if(toDraw < DT1)
  805.         base = 0;
  806.     else
  807.         base = 1;
  808.         
  809. //----------------------------------------------------------------------------------
  810. // Frame the arrow box then fill & shadow if 3D
  811. //----------------------------------------------------------------------------------
  812.  
  813.     if((**hCDEF).poly[base*3]) {
  814.         ForeColor(whiteColor);
  815.         PaintPoly((**hCDEF).poly[base*3]);
  816.         ForeColor(blackColor);
  817.         if(inColor) {
  818.             setPartColor(theCtl, cFrameColor, true);
  819.         }
  820.         FramePoly((**hCDEF).poly[base*3]);
  821.         
  822. //----------------------------------------------------------------------------------
  823. // draw shadow if 3D arrow
  824. //----------------------------------------------------------------------------------
  825.  
  826.         if(inColor && varCode & ctl3D) {
  827.             if(toDraw < DT1) {
  828.                 arrowRect = parts[FRAMET];
  829.                 OffsetRect(&arrowRect, -parts[ALL].left, -parts[ALL].top);
  830.             }
  831.             else {
  832.                 arrowRect = parts[FRAMED];
  833.                 OffsetRect(&arrowRect, -parts[ALL].left, -parts[ALL].top);
  834.             }
  835.             RGBForeColor(&rgbA);
  836.             
  837.             MoveTo(arrowRect.left+1, arrowRect.bottom-1);
  838.             LineTo(arrowRect.left-1, arrowRect.bottom-3);
  839.             LineTo(arrowRect.left-1, arrowRect.top+3);
  840.             Move(0,-1);
  841.             LineTo(arrowRect.left+2, arrowRect.top-1);
  842.             LineTo(arrowRect.right-4, arrowRect.top-1);
  843.             
  844.             ForeColor(whiteColor);
  845.             Move(1,0);
  846.             LineTo(arrowRect.right, arrowRect.top+2);
  847.             LineTo(arrowRect.right, arrowRect.bottom-3);
  848.             LineTo(arrowRect.right-3, arrowRect.bottom);
  849.             LineTo(arrowRect.left+2, arrowRect.bottom);                
  850.             
  851.             setPartColor(theCtl, cFrameColor, true);
  852.         }
  853.     }
  854.     
  855. //----------------------------------------------------------------------------------
  856. // The small, non-3D arrows are hilited by filling the top/bottom half
  857. // of the frame with the bgColor.  Then we fill/paint the arrow poly in white.
  858. //----------------------------------------------------------------------------------
  859.  
  860.     if(!(varCode & ctl3D) || !inColor) {
  861.         if((**hCDEF).arrowHilite) {
  862.             arrowRect = parts[toDraw];
  863.             OffsetRect(&arrowRect, -parts[ALL].left, -parts[ALL].top);
  864.             if(toDraw == UPDATE || toDraw == UPTIME)
  865.                 MoveTo(arrowRect.left+1, arrowRect.top+1);
  866.             else
  867.                 MoveTo(arrowRect.left+1,arrowRect.top-1);
  868.             for(inx=0;inx<8;inx++) {
  869.                 Line(8,0);
  870.                 Move(-8,1);
  871.             }
  872.         }
  873.     }
  874. //----------------------------------------------------------------------------------    
  875. // draw both the top & bottom arrows (poly[1] & poly[2])
  876. //----------------------------------------------------------------------------------
  877.  
  878.     for(inx=1;inx<3;inx++) {
  879.         if((**hCDEF).poly[base*3+inx]) {                    // Need the poly!
  880. //----------------------------------------------------------------------------------
  881. // First check to see if we are drawing a hilited arrow
  882. //----------------------------------------------------------------------------------
  883.             if(toDraw-4 == inx ||
  884.                 toDraw-9 == inx) {                            // arrow is hilited
  885.                 if(inColor) {
  886.                     if(varCode & ctl3D)
  887.                         RGBForeColor(&rgbBlack);            // in black for 3D arrows
  888.                     else
  889.                         RGBForeColor(&rgbWhite);            // in white for non-3D
  890.                 }
  891.                 else                                        // b&w hilited arrow
  892.                     ForeColor(whiteColor);                    // must draw white                
  893.                 PaintPoly((**hCDEF).poly[base*3+inx]);        // draw the arrow
  894.             }
  895. //----------------------------------------------------------------------------------
  896. // Nope, it is not hilited
  897. //----------------------------------------------------------------------------------
  898.             else                                            // make it look like a
  899.             if(varCode & ctl3D) {                            // scroll bar arrow
  900.                 if(inColor) {                                // with lighter center
  901.                     setPartColor(theCtl, cTingeLight, true);
  902.                     GetForeColor(&grayColor);
  903.                     grayColor.red -= 13107;
  904.                     grayColor.green -= 13107;
  905.                     grayColor.blue -= 13107;
  906.                     RGBForeColor(&grayColor);
  907.                     PaintPoly((**hCDEF).poly[base*3+inx]);
  908.                     setPartColor(theCtl, cTingeDark, true);
  909.                 }
  910.                 else                                        // in 3D, but in b&w
  911.                     PaintPoly((**hCDEF).poly[base*3+inx]);    // so arrow is solid fgColor
  912.             }
  913.             else                                            // not 3D, so arrow
  914.                 PaintPoly((**hCDEF).poly[base*3+inx]);        // is solid fgColor
  915.                 
  916.             FramePoly((**hCDEF).poly[base*3+inx]);            // frame the arrow
  917.         }
  918.     
  919.         if(inColor)                                            // set fg for next arrow
  920.             setPartColor(theCtl, cFrameColor, true);
  921.         else
  922.             ForeColor(blackColor);
  923.     }
  924. }
  925.  
  926. //==================================================================================
  927. //    Get the rectangles for each part of the control.  These are used for
  928. //    detecting mouse actions and hiliting the date & time digits.
  929. //==================================================================================
  930. static void getRects (ControlHandle theCtl, short varCode, Rect parts[])
  931. {
  932.     short        ht,wid,tWid,offset,inx,m,d,y;
  933.     Rect         base,work,up,down,mR,dR,yR;
  934.     FontInfo    f;
  935.     char        sStr[9];
  936.     dtcHandle    hCDEF;
  937.     
  938.     hCDEF = (dtcHandle)(**theCtl).contrlData;
  939.     if(!hCDEF)
  940.         return;
  941.     
  942.     sStr[0] = 8;                                    // sample "88/88/88"        
  943.     sStr[3] = sStr[6] = (**hCDEF).dateSep;
  944.     sStr[1] = sStr[2] = sStr[4] = sStr[5] = sStr[7] = sStr[8] = '8'; 
  945.     
  946.     getDateFmt(theCtl, &m, &d, &y);
  947.     GetFontInfo(&f);
  948.     ht = f.ascent + f.descent+f.leading;
  949.     if(f.leading == 0) 
  950.         ht++;
  951.     
  952.     base = (**theCtl).contrlRect;                    // the entire control
  953.     parts[ALL] = base;
  954.     tWid = StringWidth((**theCtl).contrlTitle);
  955.     if(tWid)
  956.         tWid+=5;        
  957.     base.left+=tWid;
  958.     parts[FONTINFO] = base;
  959.     parts[FONTINFO].bottom = ht - f.ascent;            // baseline for DrawStr        
  960.  
  961. //----------------------------------------------------------------------------------
  962. // part rectangles for Date portion of control; left justified    
  963. //----------------------------------------------------------------------------------                
  964.     
  965.     base.top = base.bottom - ARROWHT;                // resize to arrow height    
  966.     up = work = base;                                // the up arrow rect        
  967.     up.left += StringWidth((StringPtr)sStr) + 6;    // shift arrow to right        
  968.     up.right = up.left + ARROWID;                    // resize arrow width        
  969.     parts[FRAMED] = down = up;                        // up & down are full rects    
  970.     up.bottom = up.top + (up.bottom - up.top)/2;    // split them in half            
  971.     
  972.     parts[UPDATE] = up;                                // up rect is top half        
  973.     down.top = up.bottom+1;
  974.     parts[DOWNDATE] = down;                            // down rect is bottom half    
  975.     
  976.     wid = StringWidth("\p88")+2;                    // digit rect for 2 numbers    
  977.     work.right = work.left + wid;
  978.     offset = (ARROWHT - ht)/2;                        // center digits in rect    
  979.     work.bottom -= offset;
  980.     work.top = (work.bottom-ht)/2 * 2;
  981.     
  982.     parts[TITLE] = work;
  983.     parts[TITLE].left = parts[ALL].left;
  984.     tWid = StringWidth((**theCtl).contrlTitle);
  985.     if(tWid)
  986.         tWid+=5;
  987.     parts[TITLE].right = parts[TITLE].left+tWid;
  988.  
  989.     parts[DT1] = parts[DATE] = work;                // the first digits rect    
  990.     offset = CharWidth((**hCDEF).dateSep)-2;        // a bit of fudge here        
  991.     OffsetRect(&work, wid+offset,0);                // offset the other rects    
  992.     parts[DT2] = work;
  993.     OffsetRect(&work, wid+offset,0);
  994.     parts[DT3] = work;
  995.     
  996. //----------------------------------------------------------------------------------
  997. // part rectangles for Time portion of control; right justified        
  998. //----------------------------------------------------------------------------------
  999.  
  1000.     sStr[0] = 8;                                    // sample "88:88 AM"        
  1001.     sStr[3] = (**hCDEF).timeSep;
  1002.     sStr[1] = sStr[2] = sStr[4] = sStr[5] = '8';
  1003.     sStr[6] = ' '; 
  1004.     sStr[7] = 'A';
  1005.     sStr[8] = 'M';
  1006.     
  1007. //----------------------------------------------------------------------------------
  1008. // build rects for up and down portion of arrow, right justified in cntrolRect    
  1009. //----------------------------------------------------------------------------------
  1010.  
  1011.     up = base;                                        // base rect    
  1012.     OffsetRect(&up,-1,0);
  1013.     work = up;            
  1014.     up.left = up.right - ARROWID;                    // shift arrow to right        
  1015.     parts[FRAMET] = down = up;                        // up & down are full rects    
  1016.     up.bottom = up.top + (up.bottom - up.top)/2;    // split them in half            
  1017.     
  1018.     parts[UPTIME] = up;                                // up rect is top half        
  1019.     down.top = up.bottom+1;
  1020.     parts[DOWNTIME] = down;                            // down rect is bottom half    
  1021.     
  1022. //----------------------------------------------------------------------------------
  1023. // build rects for digit portion of time string    
  1024. //----------------------------------------------------------------------------------
  1025.  
  1026.     offset = (ARROWHT - ht)/2;                        // center digits in rect    
  1027.     work.bottom -= offset;
  1028.     work.top = (work.bottom-ht)/2 * 2;
  1029.     if(varCode & showAMPM)                            // set timeRect.left        
  1030.         work.left = up.left - (StringWidth((StringPtr)sStr) + 6);
  1031.     else {
  1032.         sStr[0] = 5;
  1033.         work.left = up.left - (StringWidth((StringPtr)sStr) + 6);
  1034.     }
  1035.     work.right = work.left+wid;                        // enough room for 2 digits    
  1036.     
  1037.     parts[HOURS] = work;                            // hours digit rect            
  1038.     
  1039.     offset = CharWidth((**hCDEF).timeSep)-2;        // a little fudge…            
  1040.     OffsetRect(&work,wid+offset,0);
  1041.     parts[MINUTES] = work;                            // minutes digit rect        
  1042.     
  1043.     if(varCode & showAMPM) {                        // set up AM/PM rect        
  1044.         offset = CharWidth(' ')-2;                    // a little fudge…            
  1045.         OffsetRect(&work,wid+offset,0);
  1046.         wid = StringWidth("\pPM");
  1047.         work.right = work.left+wid+2;
  1048.     }
  1049.     else
  1050.         SetRect(&work,0,0,0,0);                        // no AM/PM, so no rect        
  1051.  
  1052.     parts[AMPM] = work;
  1053.     
  1054.     
  1055. //----------------------------------------------------------------------------------
  1056. // shift rects around to match date format    
  1057. //----------------------------------------------------------------------------------    
  1058.  
  1059.     mR = parts[m+DT1];
  1060.     dR = parts[d+DT1];
  1061.     yR = parts[y+DT1];
  1062.     parts[DT1] = mR;
  1063.     parts[DT2] = dR;
  1064.     parts[DT3] = yR;
  1065.     
  1066. //----------------------------------------------------------------------------------
  1067. // shift 'em around for the time only or stacked version
  1068. //----------------------------------------------------------------------------------    
  1069.     
  1070.     if(varCode & dtStack) {                    
  1071.         offset = ht + f.descent;                        // shift date rects up 
  1072.         for(inx = DT1;inx<FONTINFO;inx++)
  1073.             OffsetRect(&parts[inx],0, - offset);
  1074.     }
  1075.     if(varCode & dtStack || varCode & timeOnly) {        // shift time rects left
  1076.         offset = parts[HOURS].left - parts[DATE].left;
  1077.         for(inx = FRAMET;inx<DT1;inx++)
  1078.             OffsetRect(&parts[inx], - offset, 0);
  1079.     }
  1080.     if(varCode & dtStack && varCode & showAMPM) {        // align arrows
  1081.         parts[UPTIME].left = parts[DOWNTIME].left = parts[DOWNDATE].left;
  1082.         parts[UPTIME].right = parts[DOWNTIME].right = parts[DOWNDATE].right;
  1083.         parts[FRAMET].left = parts[FRAMED].left;
  1084.         parts[FRAMET].right = parts[FRAMED].right;
  1085.     }
  1086. }
  1087.  
  1088. //==================================================================================
  1089. //    Convert seconds to a Pascal string containing the time
  1090. //==================================================================================
  1091. static void getTimeStr(ControlHandle theCtl, short varCode, long secs, Str31 string)
  1092. {
  1093.     short        i=0;
  1094.     long        nl;
  1095.     Str31        s;
  1096.     DateTimeRec    dtr;
  1097.     dtcHandle    hCDEF;
  1098.     
  1099.     hCDEF = (dtcHandle)(**theCtl).contrlData;
  1100.     if(!hCDEF)
  1101.         return;
  1102.     
  1103.     string[i++] = 5;                // pascal string            
  1104.     
  1105.     Secs2Date(secs,&dtr);            // convert to DateTimeRec    
  1106.  
  1107.     nl = dtr.hour;                    // convert the hours        
  1108.     if(varCode & showAMPM) {        // 12 hour display            
  1109.         if(nl > 12)
  1110.             nl-=12;
  1111.         else                        // 24 hour display            
  1112.         if(nl == 0 && ((**hCDEF).timeCycle == 0xFF))
  1113.             nl = 12;
  1114.     }
  1115.     NumToString(nl, s);
  1116.     if(nl > 9) {
  1117.         string[i++] = s[1];
  1118.         string[i++] = s[2];
  1119.     }
  1120.     else {
  1121.         string[i++] = '0';
  1122.         string[i++] = s[1];
  1123.     }
  1124.                 
  1125.     string[i++] = (**hCDEF).timeSep;
  1126.     
  1127.     nl = dtr.minute;                // convert the minutes        
  1128.     NumToString(nl, s);
  1129.     if(nl > 9) {
  1130.         string[i++] = s[1];
  1131.         string[i++] = s[2];
  1132.     }
  1133.     else {
  1134.         string[i++] = '0';
  1135.         string[i++] = s[1];
  1136.     }
  1137.     if(varCode & showAMPM) {        // fill in the AM/PM        
  1138.         string[0] = 8;                // and adjust string len    
  1139.         string[i++] = ' ';
  1140.         if(dtr.hour > 11)
  1141.             string[i++] = 'P';
  1142.         else
  1143.             string[i++] = 'A';
  1144.         string[i++] = 'M';
  1145.     }
  1146.     
  1147. }
  1148.  
  1149. //==================================================================================
  1150. // a "brain dead" little routine to return m, d, y order from Intl0 resource
  1151. //==================================================================================
  1152. static void getDateFmt(ControlHandle theCtl, short * m, short * d, short * y)
  1153. {
  1154.     Intl0Hndl    hInt;
  1155.     dtcHandle    hCDEF;
  1156.     
  1157.     hCDEF = (dtcHandle)(**theCtl).contrlData;
  1158.     if(!hCDEF)
  1159.         return;
  1160.     
  1161.     hInt = (Intl0Hndl)IUGetIntl(0);
  1162.     
  1163.     (**hCDEF).dateSep = (**hInt).dateSep;
  1164.     (**hCDEF).dateOrder = (**hInt).dateOrder;
  1165.     (**hCDEF).timeSep = (**hInt).timeSep;
  1166.     (**hCDEF).timeCycle = (**hInt).timeCycle;
  1167.     
  1168.     switch((**hCDEF).dateOrder){
  1169.         case 0:
  1170.             *m = 0;
  1171.             *d = 1;
  1172.             *y = 2;
  1173.         break;
  1174.         case 1:
  1175.             *m = 1;
  1176.             *d = 0;
  1177.             *y = 2;
  1178.         break;
  1179.         case 2:
  1180.             *m = 1;
  1181.             *d = 2;
  1182.             *y = 0;
  1183.         break;
  1184.         case 3:
  1185.             *m = 0;
  1186.             *d = 2;
  1187.             *y = 1;
  1188.         break;
  1189.         case 4:
  1190.             *m = 2;
  1191.             *d = 0;
  1192.             *y = 1;
  1193.         break;
  1194.         case 5:
  1195.             *m = 2;
  1196.             *d = 1;
  1197.             *y = 0;
  1198.         break;
  1199.     }
  1200. }
  1201. //==================================================================================
  1202. //    Convert seconds to a Pascal string containing the date, in 
  1203. //    order specified in the Date & Time Control Panel
  1204. //==================================================================================
  1205. static void getDateStr(ControlHandle theCtl, long secs, Str31 string)
  1206. {
  1207.     short        i,m,d,y,dateTbl[3];
  1208.     long        nl;
  1209.     Str31        s;
  1210.     DateTimeRec    dtr;
  1211.     dtcHandle    hCDEF;
  1212.     
  1213.     hCDEF = (dtcHandle)(**theCtl).contrlData;
  1214.     if(!hCDEF)
  1215.         return;
  1216.     
  1217.     string[0] = 8;                                // 8 byte pascal string        
  1218.     string[3] = string[6] = (**hCDEF).dateSep;
  1219.     
  1220.     Secs2Date(secs,&dtr);                        // convert to DateTimeRec    
  1221.     getDateFmt(theCtl, &m, &d, &y);                // get table indices
  1222.     dateTbl[m] = dtr.month;                        // and plug into local tbl    
  1223.     dateTbl[d] = dtr.day;
  1224.     dateTbl[y] = dtr.year;
  1225.     
  1226.     i = m*3+1;
  1227.     nl = dateTbl[m];                            // convert the month        
  1228.     NumToString(nl, s);
  1229.     
  1230.     if(nl > 9) {
  1231.         string[i++] = s[1];
  1232.         string[i]   = s[2];
  1233.     }
  1234.     else {
  1235.         string[i++] = '0';
  1236.         string[i]   = s[1];
  1237.     }
  1238.     
  1239.     i = d*3+1;
  1240.     nl = dateTbl[d];                            // convert the day            
  1241.     NumToString(nl, s);
  1242.     
  1243.     if(nl > 9) {
  1244.         string[i++] = s[1];
  1245.         string[i]   = s[2];
  1246.     }
  1247.     else {
  1248.         string[i++] = '0';
  1249.         string[i]   = s[1];
  1250.     }
  1251.     
  1252.     i = y*3+1;
  1253.     nl = dateTbl[y] - (dateTbl[y]/100 * 100);    // convert the year            
  1254.     NumToString(nl, s);
  1255.     
  1256.     if(nl > 9) {
  1257.         string[i++] = s[1];
  1258.         string[i]   = s[2];
  1259.     }
  1260.     else {
  1261.         string[i++] = '0';
  1262.         string[i]   = s[1];
  1263.     }
  1264. }
  1265.  
  1266. //==================================================================================
  1267. //    A simple check to see if a partCode is one of the up/down arrows
  1268. //==================================================================================
  1269. static char arrowPart (short partCode)
  1270. {
  1271.     if(partCode == UPTIME        ||
  1272.         partCode == DOWNTIME    ||
  1273.         partCode == UPDATE        ||
  1274.         partCode == DOWNDATE)
  1275.         return true;
  1276.     return false;
  1277. }
  1278. //==================================================================================
  1279. //    create polygons for the arrow frame and both of the arrows    
  1280. //==================================================================================
  1281.  
  1282. void makePolys(ControlHandle theCtl, short varCode)
  1283. {
  1284.     short        inx,c,v,w,b1,b2;    
  1285.     Rect        r,parts[NUMPARTS];
  1286.     dtcHandle    hCDEF;
  1287.     
  1288.     hCDEF = (dtcHandle)(**theCtl).contrlData;
  1289.     if(!hCDEF) {                                        // ooops!                    
  1290.         return;
  1291.     }
  1292.     getRects(theCtl, varCode, parts);                    // rects for control parts
  1293.     OffsetRect(&parts[FRAMET],                             // adjust to 0,0            
  1294.                 -parts[ALL].left, -parts[ALL].top);    
  1295.     r = parts[FRAMET];
  1296.     
  1297.     for(inx=0;inx<2;inx++) {
  1298.         (**hCDEF).poly[3*inx] = OpenPoly();                // frame the arrows
  1299.         
  1300.         if((**hCDEF).poly[3*inx]) {
  1301.             MoveTo(r.left+2,r.top);    
  1302.             LineTo(r.right-3, r.top);
  1303.             Line(2,3);
  1304.             LineTo(r.right-1, r.bottom-3);
  1305.             Line(-2,2);
  1306.             LineTo(r.left+2, r.bottom-1);
  1307.             Line(-2,-2);
  1308.             LineTo(r.left, r.top+3);
  1309.             Line(2,-3);
  1310.             ClosePoly();
  1311.         }
  1312.         
  1313.         c = (r.right - r.left)/2 + r.left;
  1314.         b1 = (r.right - r.left -2)/3;
  1315.         b2 = (r.right - r.left -2)/4;
  1316.         v = r.top+2;
  1317.         w = b2;
  1318.         
  1319.         (**hCDEF).poly[3*inx+1] = OpenPoly();            // draw UP arrow
  1320.         
  1321.         if((**hCDEF).poly[3*inx+1]) {
  1322.             MoveTo(c,v);
  1323.             Line(-b1,b1);
  1324.             Line(2,0);
  1325.             Line(0,b2);
  1326.             Line(w,0);
  1327.             Line(0,-b2);
  1328.             Line(2,0);
  1329.             Line(-b1,-b1);
  1330.             ClosePoly();
  1331.         }
  1332.             
  1333.         v = r.bottom-3;
  1334.         (**hCDEF).poly[3*inx+2] = OpenPoly();            // draw DOWN arrow
  1335.         
  1336.         if((**hCDEF).poly[3*inx+2]) {        
  1337.             MoveTo(c,v);
  1338.             Line(-b1,-b1);
  1339.             Line(2,0);
  1340.             Line(0,-b2);
  1341.             Line(w,0);
  1342.             Line(0,b2);
  1343.             Line(2,0);
  1344.             Line(-b1,b1);
  1345.             ClosePoly();
  1346.         }
  1347.         OffsetRect(&parts[FRAMED],                         // adjust to 0,0            
  1348.                     -parts[ALL].left, -parts[ALL].top);    
  1349.         r = parts[FRAMED];
  1350.     }
  1351. }
  1352.